using System;
using System.Collections;
using UnityEngine;

namespace EventBehaviorTree
{
    [Serializable]
    public class ConditionSequencer : Container
    {
        private ConditionPattern _pattern;
        private Func<bool> Condition = delegate { return false; };
        private int _duration;
        private int _remainFrame;
        private IEnumerator _checkCondition;
        private Action ON_Reset = delegate { };
        public int Duration { get => _duration; set => _duration = Mathf.Max(0, value); }
        public int RemainFrame { get => _remainFrame; set => _remainFrame = Mathf.Max(0, value); }
        public ConditionSequencer() { _pattern = ConditionPattern.Watcher; }
        public ConditionSequencer(string duration) { Duration = int.Parse(duration); _pattern = ConditionPattern.TriggerTimer; }
        public override void Initialize(MonoBehaviour behaviorTree)
        {
            base.Initialize(behaviorTree);
            _checkCondition = null;
        }
        public void SetNodeFunction(ICondition INodeFunction)
        {
            Condition = INodeFunction.Condition;
            ON_Reset += INodeFunction.ResetCondition;
        }
        IEnumerator CheckCondition()
        {
            switch (_pattern)
            {
                case ConditionPattern.Watcher:
                    while (!Condition()) { yield return null; }//when it is true, break
                    SubNodeCheck();
                    Reset();
                    break;
                case ConditionPattern.TriggerTimer:
                    RemainFrame = Duration;
                    while (RemainFrame > 0)//wait for a while
                    {
                        if (!Condition())
                        {
                            RemainFrame--;
                            Debug.Log("TT");
                            yield return new WaitForSeconds(0);
                        }
                        else
                        {
                            SubNodeCheck();
                            Reset();
                        }
                    }
                    Reset();
                    CompositeNodeEvent(NodeMessage.Failure);
                    break;
                default:
                    break;
            }
        }
        public override void NodeEvent(NodeMessage nodeMessage)
        {
            switch (nodeMessage)
            {
                case NodeMessage.Start:
                    if (_checkCondition == null)
                    {
                        //Reset();
                        _checkCondition = CheckCondition();
                        _monoBehavior.StartCoroutine(_checkCondition);
                    }
                    else
                    {
                        _stepCounter = 0;
                        _subNodes[_stepCounter].NodeEvent(NodeMessage.Start);
                    }
                    return;
                case NodeMessage.Success:
                    _stepCounter++;
                    if (_stepCounter < _subNodes.Count)
                    {
                        _subNodes[_stepCounter].NodeEvent(NodeMessage.Start);
                        return;
                    }
                    break;
                case NodeMessage.COMMAND_Stop:
                    Reset();
                    foreach (EventNode subNode in _subNodes) { subNode.NodeEvent(NodeMessage.COMMAND_Stop); }
                    return;
                default:
                    break;
            }
            Reset();
            CompositeNodeEvent(nodeMessage);//send message and stop the sequence
        }
        public override void Reset()
        {
            base.Reset();
            if (_checkCondition != null)
            {
                _monoBehavior.StopCoroutine(_checkCondition);
                _checkCondition = null;
            }
            ON_Reset();
        }
    }
}
